#pragma once

#include<cstdlib>
#include<queue>
#include<pthread.h>
#include<iostream>
using namespace std;
#include<sys/types.h>
#include<unistd.h>

const uint32_t gDefaultCap=5;
template<class T>
class BlockQueue
{
public:
    BlockQueue(uint32_t cap=gDefaultCap):cap_(cap)
    {
        pthread_mutex_init(&mutex_,nullptr);
        pthread_cond_init(&conCond_,nullptr);
        pthread_cond_init(&proCond_,nullptr);
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&conCond_);
        pthread_cond_destroy(&proCond_);
    }
    void push(const T& in)
    {
        lockQueue();
        while(isFull())
        {
            proBlockWait();
        }
        //满足条件，可以继续生产
        pushCore(in);
        unlockQueue();
        pthread_cond_signal(&conCond_);
    }
    T pop()
    {
        lockQueue();
        while(isEmpty())
        {
            conBlockWait();
        }
        //满足条件，可以继续生产
        T tmp=popCore();
        unlockQueue();
        pthread_cond_signal(&proCond_);
        return tmp;
    }
private:

    void lockQueue()
    {
        pthread_mutex_lock(&mutex_);
    }
    void unlockQueue()
    {
        pthread_mutex_unlock(&mutex_);
    }
    bool isFull()
    {
        return bq_.size()==cap_;
    }
    bool isEmpty()
    {
        return bq_.empty();
    }
    void conBlockWait()
    {
        pthread_cond_wait(&conCond_,&mutex_);
    }
    void proBlockWait()
    {
        pthread_cond_wait(&proCond_,&mutex_);
    }
    void pushCore(const T& in)
    {
        bq_.push(in);
    }
    T popCore()
    {
        T tmp=bq_.front();
        bq_.pop();
        //cout<<"消费————"<<endl;
        return tmp;
    }
private:
    uint32_t cap_;
    queue<T> bq_;
    pthread_mutex_t mutex_;
    pthread_cond_t conCond_;
    pthread_cond_t proCond_;
};